package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.service.ApArticleConfigService;
import com.heima.article.service.ApArticleContentService;
import com.heima.article.service.ApCollectionService;
import com.heima.common.constant.ArticleConstant;
import com.heima.common.constant.GlobalConstant;
import com.heima.common.exception.CustomException;
import com.heima.model.article.dots.*;
import com.heima.model.article.pojos.ApArticle;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.pojos.ApCollection;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.behavior.vo.BehaviorVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.threadLocal.AppThreadLocalUtil;
import freemarker.template.TemplateException;
import org.apache.avro.data.Json;
import org.bouncycastle.cert.ocsp.Req;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.StringReader;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    ApArticleMapper apArticleMapper;
    @Autowired
    ApArticleConfigService apArticleConfigService;
    @Autowired
    ApArticleContentService apArticleContentService;
    @Autowired
    KafkaTemplate kafkaTemplate;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ApCollectionService apCollectionService;
    @Override
    public ResponseResult load(ArticleHomeDto dto) {
        if (dto==null)
        {
            throw new CustomException(AppHttpCodeEnum.PARAMS_NOT_NULL);
        }
        if(dto.getMaxBehotTime()==null)
            dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime()==null)
            dto.setMinBehotTime(new Date());
        if(dto.getSize()==null||dto.getSize()<=0)
            dto.setSize(10);
        dto.setSize(Math.min(dto.getSize(), GlobalConstant.MAX_PAGE_SIZE));
        if(dto.getTag()==null)
            dto.setTag(ArticleConstant.DEFAULT_TAG);
        if (dto.getType()==null||
                (
                        !dto.getType().equals(ArticleConstant.LOADTYPE_LOAD_NEW)
                        &&!dto.getType().equals(ArticleConstant.LOADTYPE_LOAD_MORE)
                )
        )
            dto.setType(ArticleConstant.LOADTYPE_LOAD_MORE);
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto);
        return ResponseResult.okResult(apArticles);
    }

    @Override
    public ResponseResult saveOrUpdateArticleAndConfig(ArticleDto dto){
        if(dto==null)
        {
            throw new RuntimeException(AppHttpCodeEnum.PARAMS_NOT_NULL.getErrorMessage());
        }
        ApArticleContent apArticleContent=new ApArticleContent();
        if(dto.getId()==null)
        {
            dto.setLikes(0);
            dto.setCollection(0);
            dto.setComment(0);
            dto.setViews(0);
            this.save(dto);
            ApArticleConfig apArticleConfig = new ApArticleConfig();
            apArticleConfig.setArticleId(dto.getId());
            apArticleConfigService.save(apArticleConfig);
            apArticleContent.setArticleId(dto.getId());
            apArticleContent.setContent(dto.getContent());
            apArticleContentService.save(apArticleContent);
        }
        else {

            apArticleContent.setContent(dto.getContent());
            apArticleContentService.update(Wrappers.<ApArticleContent>lambdaUpdate().eq(ApArticleContent::getArticleId,dto.getId()).set(ApArticleContent::getContent,dto.getContent()));
            ApArticle article = this.getById(dto.getId());
            apArticleContentService.deleteContentHtml(article.getStaticUrl());
        }
        String url = null;
        try {
            url = apArticleContentService.generateContentHtml(apArticleContent);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (TemplateException e) {
            throw new RuntimeException(e);
        }
        dto.setStaticUrl(url);
        this.updateById(dto);
        sendMessageToEs(dto);
        return ResponseResult.okResult(dto.getId());
    }

    @Override
    public ResponseResult collectionBehavior(CollectionBehaviorDto dto) {
        if (dto==null||dto.getType()==null||dto.getEntryId()==null||dto.getOperation()==null||dto.getPublishedTime()==null)
        {
            throw new CustomException(AppHttpCodeEnum.PARAMS_NOT_NULL);
        }
        if (!CollectionBehaviorDto.Type.check(dto.getType())||!CollectionBehaviorDto.Operation.check(dto.getOperation()))
        {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (dto.getType().equals(CollectionBehaviorDto.Type.DYNAMIC))
        {
            //TODO 收藏动态待开发
            throw new CustomException(AppHttpCodeEnum.FUNCTION_TO_BE_DEVELOPED);
        }
        UpdateArticleMsg updateArticleMsg = new UpdateArticleMsg();
        updateArticleMsg.setArticleId(dto.getEntryId());
        if (dto.getOperation().equals(CollectionBehaviorDto.Operation.COLLECTION.getValue()))
        {
            ApCollection one = apCollectionService.getOne(Wrappers.<ApCollection>lambdaQuery()
                    .eq(ApCollection::getArticleId, dto.getEntryId())
                    .eq(ApCollection::getType, dto.getType())
                    .eq(ApCollection::getEntryId, AppThreadLocalUtil.getUserId()));
            if (one!=null)
            {
                throw new CustomException(AppHttpCodeEnum.FAIL);
            }
            ApCollection apCollection=new ApCollection();
            apCollection.setArticleId(dto.getEntryId());
            apCollection.setCollectionTime(new Date());
            apCollection.setPublishedTime(dto.getPublishedTime());
            apCollection.setEntryId(AppThreadLocalUtil.getUserId());
            apCollection.setType(dto.getType());
            boolean b = apCollectionService.save(apCollection);
            if (b)
            {
//                this.update(Wrappers.<ApArticle>lambdaUpdate()
//                        .eq(ApArticle::getId,dto.getEntryId())
//                        .setSql("collection=collection+1"));
                updateArticleMsg.setCollection(1);
                String key=GlobalConstant.ARTICLE_COLLECTION_PREFIX+dto.getEntryId();
                stringRedisTemplate.opsForSet().add(key,AppThreadLocalUtil.getUserId().toString());
            }
            else return ResponseResult.errorResult();

        }
        else {
            boolean b = apCollectionService.remove(Wrappers.<ApCollection>lambdaQuery()
                    .eq(ApCollection::getArticleId, dto.getEntryId())
                    .eq(ApCollection::getType, dto.getType())
                    .eq(ApCollection::getEntryId, AppThreadLocalUtil.getUserId()));
            if(b)
            {
//                this.update(Wrappers.<ApArticle>lambdaUpdate()
//                        .eq(ApArticle::getId,dto.getEntryId())
//                        .setSql("collection=collection-1"));
                updateArticleMsg.setCollection(-1);
                String key=GlobalConstant.ARTICLE_COLLECTION_PREFIX+dto.getEntryId();
                stringRedisTemplate.opsForSet().remove(key,AppThreadLocalUtil.getUserId().toString());
            }
            else return ResponseResult.errorResult();

        }
        kafkaTemplate.send(GlobalConstant.HOT_ARTICLE_SCORE_STREAM_TOPIC,JSON.toJSONString(updateArticleMsg));
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
        if (dto==null||dto.getArticleId()==null||dto.getAuthorId()==null)
        {
            throw new CustomException(AppHttpCodeEnum.PARAMS_NOT_NULL);
        }
        String likeKey=GlobalConstant.ARTICLE_LIKE_PREFIX+dto.getArticleId();
        String noLikeKey=GlobalConstant.ARTICLE_NO_LIKE_PREFIX+dto.getArticleId();
        String collectionKey=GlobalConstant.ARTICLE_COLLECTION_PREFIX+dto.getArticleId();
        String followKey=GlobalConstant.FOLLOW_PREFIX+dto.getAuthorId();
        String userId = AppThreadLocalUtil.getUserId().toString();
        BehaviorVo behaviorVo = new BehaviorVo();
        behaviorVo.setIslike(stringRedisTemplate.opsForSet().isMember(likeKey,userId));
        behaviorVo.setIsunlike(stringRedisTemplate.opsForSet().isMember(noLikeKey,userId));
        behaviorVo.setIscollection(stringRedisTemplate.opsForSet().isMember(collectionKey,userId));
        behaviorVo.setIsfollow(stringRedisTemplate.opsForSet().isMember(followKey,userId));
        return ResponseResult.okResult(behaviorVo);
    }

    @Override
    public ResponseResult loadHot(ArticleHomeDto dto) {
        if (dto==null)
        {
            throw new CustomException(AppHttpCodeEnum.PARAMS_NOT_NULL);
        }
        if(dto.getMaxBehotTime()==null)
            dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime()==null)
            dto.setMinBehotTime(new Date());
        if(dto.getSize()==null||dto.getSize()<=0)
            dto.setSize(10);
        dto.setSize(Math.min(dto.getSize(), GlobalConstant.MAX_PAGE_SIZE));
        if(dto.getTag()==null)
            dto.setTag(ArticleConstant.DEFAULT_TAG);
        if (dto.getType()==null||
                (
                        !dto.getType().equals(ArticleConstant.LOADTYPE_LOAD_NEW)
                                &&!dto.getType().equals(ArticleConstant.LOADTYPE_LOAD_MORE)
                )
        )
            dto.setType(ArticleConstant.LOADTYPE_LOAD_MORE);
        String key=GlobalConstant.HOT_TAG+dto.getTag();
        List<String> range = stringRedisTemplate.opsForList().range(key, 0, dto.getSize()-1);
        List<ApArticle> apArticles = range.stream().map(item -> JSON.parseObject(item, HotArticleVo.class)).collect(Collectors.toList());
        if (apArticles.size()<dto.getSize())
        {
            List<ApArticle> result = apArticleMapper.loadArticleList(dto);
            List<Long> ids = apArticles.stream().map(item -> item.getId()).collect(Collectors.toList());
            for (ApArticle article : result) {
                if (ids.contains(article.getId()))
                    continue;
                apArticles.add(article);
                if (apArticles.size()>=dto.getSize())
                    break;
            }
        }
        return ResponseResult.okResult(apArticles);
    }


    private void sendMessageToEs(ArticleDto dto){
        SearchArticleVo searchArticleVo = new SearchArticleVo();
        BeanUtils.copyProperties(dto,searchArticleVo);
        searchArticleVo.setLayout(Integer.valueOf(dto.getLayout()));
        kafkaTemplate.send(ArticleConstant.ARTICLE_ES_SYNC_TOPIC, JSON.toJSONString(searchArticleVo));
    }


}
